#include "application.h"
#include "network.h"
#include "timer.h"
#include "nethandler.h"
#include "crossobjectmgr.h"
#include "client.h"
#include "globalvar.h"
#include "luaexport.h"
#include "printer.h"
#include "server.h"
#include "netfilter.h"
#include "threadtask.h"
#include <time.h>
#include <typeinfo>
#include "google/protobuf/stubs/common.h"

class AppLuaPlatSystem:public Lua::PlatSystem
{
public:
    virtual void print(const char* s)
    {
        GPrinter->luaprint(s);
    }
};

bool AppStateInit::Run(Application* app)
{
    if(!GPrinter)
        return false;
    GLuaState=Lua::LuaOpenLua();
    delete Lua::GPlatSystem;
    Lua::GPlatSystem=new AppLuaPlatSystem;
    if(!Lua::LuaDoFile(GLuaState,"init.lua"))
    {
        GPrinter->error("Load init.lua fail!");
        return false;
    }
    GTimer=new Cross::GlobalTimer(GVar.NowTick);
    GRealTimer=new Cross::RealTimer(GVar.NowDate);
    GObjectMgr=new CrossObjectMgr();
    GTaskProcessor=new Cross::TaskProcessor(_taskThreadNum);
    GTaskProcessor->Start();
    GFilterMgr=app->CreateNetFilterManager();
    GClientMgr=app->CreateClientManager();
    GServerMgr=app->CreateServerManager();
    return GServerMgr->Initialize();
}

bool AppStateToClient::Run(Application* app)
{
    if(!Lua::LuaDoFile(GLuaState,"main.lua"))
    {
        GPrinter->error("Load main.lua fail!");
        return false;
    }
    GNet=new MsgServer();
    GNet->sethandler(GClientMgr->CreateMsgHandler());
    GNet->start(nullptr,app->GetServerPort());
    return true;
}

bool AppStateStarted::Run(Application* app)
{
    if(GNet)
        GNet->runloop();
    if(GCNet)
        GCNet->runloop();
    GTimer->Tick(GVar.NowTick);
    GObjectMgr->Tick();
    GRealTimer->Tick(GVar.NowDate);
    GTaskProcessor->Tick();
    return true;
}

bool AppStateShutdown::Run(Application* app)
{
    if(GNet)
    {
        GNet->stop();
        delete GNet;
        GNet=nullptr;
    }
    return true;
}

bool AppStateExit::Run(Application* app)
{
    if(GPrinter)
    {
        STLStringStream ss;
        ss<<"CrossObject.CurrentCode="<<CrossObject::GetCurrentCode();
        GPrinter->print(ss.str().c_str());
    }
    if(GServerMgr)
        GServerMgr->stop();
    if(GCNet)
    {    
        GCNet->stop();
        delete GCNet;
        GCNet=nullptr;
    }
    google::protobuf::ShutdownProtobufLibrary();
    Cross::delete_safe(GServerMgr);
    Cross::delete_safe(GClientMgr);
    Cross::delete_safe(GFilterMgr);
    if(GTaskProcessor)
    {
        GTaskProcessor->Stop();
        delete GTaskProcessor;
        GTaskProcessor=nullptr;
    }
    Cross::delete_safe(GObjectMgr);
    Cross::delete_safe(GRealTimer);
    Cross::delete_safe(GTimer);
    if(GLuaState)
    {
        Lua::LuaCloseLua(GLuaState);
        GLuaState=nullptr;
    }
    app->SetRunning(false);
    return true;
}

bool AppStateToServer::Run(Application* app)
{
    GCNet=new MsgClient();
    GCNet->sethandler(GServerMgr->CreateMsgHandler());
    GCNet->start();
    GServerMgr->Start(_waitConnect);
    return true;
}

Application::~Application()
{
    delete _stateFunc;
    _stateFunc=nullptr;
    delete _prevState;
    _prevState=nullptr;
    delete _nextState;
    _nextState=nullptr;
}

Application::Application()
{
    _stateFunc=nullptr;
    _prevState=nullptr;
    _nextState=nullptr;
    _sid=SID_NONE;
    _running=false;
    _port=0;
}

void Application::Shutdown()
{
    SetNextState(CreateShutdownState());
}

void Application::NextAppState()
{
    if(_nextState)
    {
        delete _prevState;
        _prevState=_stateFunc;
        _stateFunc=_nextState;
        _nextState=nullptr;
    }
}

void Application::SetNextState(AppStateFunc* appState)
{
    delete _nextState;
    _nextState=appState;
}

bool Application::Initialize(AppStateInit* appState)
{   
    SetRunning(true);
    srand((uint32)time(0));
    GVar.NowTick=GetMiniSecond();
    GVar.LastTick=GVar.NowTick;
    GVar.NowSecond=Cross::GetCurrentSecond();
    SecondToDateTime(GVar.NowSecond,GVar.NowDate);
    SetNextState(appState);
    NextAppState();
    return true;
}

void Application::MainLoop()
{
    GVar.LastTick=GVar.NowTick;
    GVar.NowTick=GetMiniSecond();
    GVar.NowSecond=Cross::GetCurrentSecond();
    SecondToDateTime(GVar.NowSecond,GVar.NowDate);
    if(GVar.NowTick>GVar.LastTick)
    {
        if(_stateFunc)
        {
            _stateFunc->Run(this);
            NextAppState();
        }
    }
}

ClientManager* Application::CreateClientManager()
{
    return new ClientManager;
}

ServerManager* Application::CreateServerManager()
{
    return new ServerManager;
}

NetFilterManager* Application::CreateNetFilterManager()
{
    return new NetFilterManager;
}

AppStateShutdown* Application::CreateShutdownState()
{
    return new AppStateShutdown;
}

void ShowCrossObjectLeak(CrossObject* obj)
{
    STLStringStream ss;
    ss<<"CrossObject leak,(code,type)="<<obj->Code()<<","<<typeid(*obj).name();
    GPrinter->error(ss.str().c_str());
}
